home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockDeliciousService.js < prev    next >
Text File  |  2007-10-18  |  28KB  |  750 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16.  
  17. const CC = Components.classes;
  18. const CI = Components.interfaces;
  19. const CR = Components.results;
  20. const CU = Components.utils;
  21.  
  22. CU.import("resource:///modules/FlockXPCOMUtils.jsm");
  23. FlockXPCOMUtils.debug = false;
  24.  
  25. CU.import("resource:///modules/FlockSvcUtils.jsm");
  26. CU.import("resource:///modules/deliciousApi.jsm");
  27. CU.import("resource:///modules/onlineFavoritesBackend.jsm");
  28.  
  29. const MODULE_NAME = "Delicious";
  30.  
  31. const CLASS_NAME = "Flock Delicious Service";
  32. const CLASS_SHORT_NAME = "delicious";
  33. const CLASS_TITLE = "del.icio.us";
  34. const CLASS_ID = Components.ID("{5c54771f-2628-4200-af16-f94609177abd}");
  35. const CONTRACT_ID = "@flock.com/delicious-service;1";
  36.  
  37. const SERVICE_ENABLED_PREF = "flock.service.delicious.enabled";
  38.  
  39. const DELICIOUS_URL = "http://del.icio.us";
  40. const DELICIOUS_FAVICON = "http://del.icio.us/favicon.ico";
  41. const DELICIOUS_API_URL = "https://api.del.icio.us/v1/";
  42. const DELICIOUS_USER_URL_BASE = "http://del.icio.us";
  43.  
  44. const PREFERENCES_CONTRACTID = "@mozilla.org/preferences-service;1";
  45. const PREFS = CC[PREFERENCES_CONTRACTID].getService(CI.nsIPrefBranch);
  46.  
  47. const DELICIOUS_STRING_BUNDLE = "chrome://flock/locale/services/delicious.properties";
  48.  
  49. // migration constants
  50. const WEBSERVICE_PREF = "flock.favorites.webservice.id";
  51. const OLD_DELICIOUS_PW_HOST = ":favorites:webservice:delicious:";
  52.  
  53. // One second, expressed in nsITimer terms.
  54. const TIMER_SECOND = 1000;
  55.  
  56. /**************************************************************************
  57.  * Component: Flock Delicious Service
  58.  **************************************************************************/
  59.  
  60. // Constructor.
  61. function flockDeliciousService() {
  62.   this._init();
  63.  
  64.   FlockSvcUtils.flockIWebService.addDefaultMethod(this, "getAccount");
  65.   FlockSvcUtils.flockIWebService.addDefaultMethod(this, "getAccounts");
  66.   FlockSvcUtils.flockIWebService.addDefaultMethod(this, "logout");
  67.  
  68.   FlockSvcUtils.flockIManageableWebService
  69.                .addDefaultMethod(this, "docRepresentsSuccessfulLogin");
  70.   FlockSvcUtils.flockIManageableWebService
  71.                .addDefaultMethod(this, "getAccountIDFromDocument");
  72.   FlockSvcUtils.flockIManageableWebService
  73.                .addDefaultMethod(this, "getCredentialsFromForm");
  74.   FlockSvcUtils.flockIManageableWebService
  75.                .addDefaultMethod(this, "ownsDocument");
  76.   FlockSvcUtils.flockIManageableWebService
  77.                .addDefaultMethod(this, "ownsLoginForm");
  78. }
  79.  
  80.  
  81. /**************************************************************************
  82.  * Flock Delicious Service: XPCOM Component Creation
  83.  **************************************************************************/
  84.  
  85. flockDeliciousService.prototype = new FlockXPCOMUtils.genericComponent(
  86.   CLASS_NAME,
  87.   CLASS_ID,
  88.   CONTRACT_ID,
  89.   flockDeliciousService,
  90.   CI.nsIClassInfo.SINGLETON,
  91.   [
  92.     CI.nsIObserver,
  93.     CI.nsITimerCallback,
  94.     CI.flockIWebService,
  95.     CI.flockIManageableWebService,
  96.     CI.flockIBookmarkWebService,
  97.     CI.flockIPollingService,
  98.     CI.flockIMigratable
  99.   ]
  100. );
  101.  
  102. // FlockXPCOMUtils.genericModule() categories
  103. flockDeliciousService.prototype._xpcom_categories = [
  104.   { category: "wsm-startup" },
  105.   { category: "flockMigratable" },
  106.   { category: "flockWebService", entry: CLASS_SHORT_NAME }
  107. ];
  108.  
  109. /**************************************************************************
  110.  * Flock Delicious Service: Private Data and Functions
  111.  **************************************************************************/
  112.  
  113. // Member variables.
  114. flockDeliciousService.prototype._init =
  115. function DeliciousSvc__init() {
  116.   FlockSvcUtils.getLogger(this).info(".init()");
  117.  
  118.   // Determine whether this service has been disabled, and unregister if so.
  119.   prefService = CC["@mozilla.org/preferences-service;1"]
  120.                 .getService(CI.nsIPrefBranch);
  121.   if (prefService.getPrefType(SERVICE_ENABLED_PREF) &&
  122.      !prefService.getBoolPref(SERVICE_ENABLED_PREF))
  123.   {
  124.     this._logger.info("Pref " + SERVICE_ENABLED_PREF
  125.                               + " set to FALSE... not initializing.");
  126.     this.deleteCategories();
  127.     return;
  128.   }
  129.  
  130.   profiler = CC["@flock.com/profiler;1"].getService(CI.flockIProfiler);
  131.   var evtID = profiler.profileEventStart("delicious-init");
  132.  
  133.   var obs = CC["@mozilla.org/observer-service;1"]
  134.             .getService(CI.nsIObserverService);
  135.   obs.addObserver(this, "xpcom-shutdown", false);
  136.  
  137.   this._api = new DeliciousAPI(DELICIOUS_API_URL, this._logger);
  138.   this._accountClassCtor = flockDeliciousAccount;
  139.   FlockSvcUtils.getACUtils(this);
  140.   FlockSvcUtils.getCoop(this);
  141.   if (this._coop.Service.exists(this.urn)) {
  142.     this._c_svc = this._coop.get(this.urn);
  143.   } else {
  144.     this._c_svc = new this._coop.Service(this.urn, {
  145.       name: CLASS_SHORT_NAME,
  146.       desc: CLASS_TITLE
  147.     });
  148.   }
  149.   this._c_svc.serviceId = CONTRACT_ID;
  150.   this._c_svc.logoutOption = false;
  151.   this._c_svc.domains = FlockSvcUtils.getWD(this)
  152.                         .getString("delicious", "domains", "icio.us");
  153.  
  154.   profiler.profileEventEnd(evtID, "");
  155. }
  156.  
  157. // Helper to retrieve tags on server.
  158. flockDeliciousService.prototype._getAllTags =
  159. function DeliciousSvc__getAllTags(aUrn, aAccountId,
  160.                                   aPassword, aPollingListener) {
  161.   this._logger.debug("getAllTags(...)");
  162.   var svc = this;
  163.  
  164.   var flockListener = {
  165.     onStart: function DeliciousSvc__getAllTags_onStart(aSubject, aTopic) {
  166.       // Not used.
  167.     },
  168.     onSuccess: function DeliciousSvc__getAllTags_onSuccess(aSubject, aTopic) {
  169.       svc._logger.info("tags/get SUCCEEDED: " + aTopic);
  170.  
  171.       var tags = [];
  172.       for (var i = 0; i < aSubject.length; i++) {
  173.         tags.push(aSubject[i].tag);
  174.       }
  175.       onlineFavoritesBackend.updateTags(svc, aAccountId, tags);
  176.  
  177.       // Tell the poller we're done
  178.       if (aPollingListener) {
  179.         aPollingListener.onResult();
  180.       }
  181.     },
  182.     onError: function DeliciousSvc__getAllTags_onError(aSubject, aTopic, aError) {
  183.       svc._logger.error("tags/get FAILED");
  184.       // BUG: 5705 -  report error via notification bar?
  185.       // onlineFavoritesBackend.showNotification(message);
  186.       if (aPollingListener) {
  187.         aPollingListener.onError(aError);
  188.       }
  189.     }
  190.   }
  191.  
  192.   this._api.tagsGet(flockListener, null);
  193. }
  194.  
  195. // Perform the version upgrade migration.
  196. flockDeliciousService.prototype._migrateDeliciousAccount =
  197. function DeliciousSvc_migrateDeliciousAccount(aContext) {
  198.   var pm = CC["@mozilla.org/passwordmanager;1"]
  199.            .getService(CI.nsIPasswordManager);
  200.   var pw = this._acUtils.getFirstPasswordForHost(OLD_DELICIOUS_PW_HOST);
  201.  
  202.   // migrate online bm privacy settings
  203.   PREFS.setBoolPref("flock.favorites.do." + CONTRACT_ID + "--" + pw.user, true);
  204.   PREFS.setBoolPref("flock.favorites.private." + CONTRACT_ID + "--" + pw.user,
  205.                     PREFS.getBoolPref("flock.favorites.privateByDefault"));
  206.  
  207.   var accountURN = this.urn + ":" + pw.user;
  208.   pm.addUser(accountURN, pw.user, pw.password);
  209.   pm.removeUser(OLD_DELICIOUS_PW_HOST, pw.user);
  210.   var acct = this.addAccountById(pw.user, false, null);
  211.   acct.activate(null);
  212.   acct.keep(null);
  213.  
  214.   yield true;
  215. }
  216.  
  217.  
  218. /**************************************************************************
  219.  * Flock Delicious Service: flockIWebService Implementation
  220.  **************************************************************************/
  221.  
  222. // readonly attribute AString urn;
  223. flockDeliciousService.prototype.urn = "urn:" + CLASS_SHORT_NAME + ":service";
  224.  
  225. // readonly attribute AString title;
  226. flockDeliciousService.prototype.title = CLASS_TITLE;
  227.  
  228. // readonly attribute AString icon;
  229. flockDeliciousService.prototype.icon = DELICIOUS_FAVICON;
  230.  
  231. // readonly attribute AString url;
  232. flockDeliciousService.prototype.url = DELICIOUS_URL;
  233.  
  234. // readonly attribute AString contractId;
  235. // ALMOST duplicated by nsIClassInfo::contractID
  236. // with different case: contractId != contractID
  237. // FIXME: File a bug for this as IDL is case-insensitive.
  238. flockDeliciousService.prototype.contractId = CONTRACT_ID;
  239.  
  240. // readonly attribute AString shortName;
  241. flockDeliciousService.prototype.shortName = CLASS_SHORT_NAME;
  242.  
  243. // readonly attribute boolean needPassword;
  244. flockDeliciousService.prototype.needPassword = true;
  245.  
  246. // flockIWebServiceAccount addAccountById(in AString aAccountID,
  247. //                                        in boolean aIsTransient,
  248. //                                        in flockIListener aListener);
  249. flockDeliciousService.prototype.addAccountById =
  250. function DeliciousSvc_addAccountById(aAccountID, aIsTransient, aListener) {
  251.   this._logger.debug("addAccountById('" + aAccountID + "', "
  252.                      + aIsTransient + ", aListener)");
  253.   var acct = onlineFavoritesBackend.createAccount(this,
  254.                                                   aAccountID, aIsTransient);
  255.   if (aListener) {
  256.     aListener.onSuccess(acct, "addAccount");
  257.   }
  258.   return acct;
  259. }
  260.  
  261. // void removeAccount(in AString aUrn);
  262. flockDeliciousService.prototype.removeAccount =
  263. function DeliciousSvc_removeAccount(aUrn) {
  264.   this._logger.debug("removeAccount('" + aUrn + "')");
  265.   onlineFavoritesBackend.removeAccount(this, aUrn);
  266. }
  267.  
  268. // DEFAULT: flockIWebServiceAccount getAccount(in AString aUrn);
  269. // DEFAULT: nsISimpleEnumerator getAccounts();
  270. // DEFAULT: void logout();
  271.  
  272. // readonly attribute long status;
  273. flockDeliciousService.prototype.status = CI.flockIWebService.STATUS_UNKNOWN;
  274.  
  275.  
  276. /**************************************************************************
  277.  * Flock Delicious Service: flockIManageableWebService Implementation
  278.  **************************************************************************/
  279.  
  280. // DEFAULT: boolean docRepresentsSuccessfulLogin(in nsIDOMHTMLDocument aDocument);
  281. // DEFAULT: AString getAccountIDFromDocument(in nsIDOMHTMLDocument aDocument);
  282. // DEFAULT: nsIPassword getCredentialsFromForm(in nsIDOMHTMLFormElement aForm);
  283. // DEFAULT: boolean ownsDocument(in nsIDOMHTMLDocument aDocument);
  284. // DEFAULT: boolean ownsLoginForm(in nsIDOMHTMLFormElement aForm);
  285.  
  286. // void updateAccountStatusFromDocument(in nsIDOMHTMLDocument aDocument);
  287. flockDeliciousService.prototype.updateAccountStatusFromDocument =
  288. function DeliciousSvc_updateAccountStatusFromDocument(aDocument) {
  289.   this._logger.debug("updateAccountStatusFromDocument()");
  290.  
  291.   if (this._WebDetective.detect("delicious", "loggedout", aDocument, null)) {
  292.     this._acUtils.markAllAccountsAsLoggedOut(CONTRACT_ID);
  293.   } else {
  294.     if (this._WebDetective.detect("delicious", "loggedin", aDocument, null)) {
  295.       var results = FlockSvcUtils.newResults();
  296.       if (this._WebDetective.detect("delicious",
  297.                                     "accountinfo", aDocument, results))
  298.       {
  299.         var accountID = results.getPropertyAsAString("accountid");
  300.         var accountURN = this._acUtils.getAccountURNById(this.urn, accountID);
  301.         this._acUtils.ensureOnlyAuthenticatedAccount(accountURN);
  302.       }
  303.     }
  304.   }
  305. }
  306.  
  307. /**************************************************************************
  308.  * Flock Delicious Service: flockIBookmarkWebService Implementation
  309.  **************************************************************************/
  310.  
  311. // void publish (in flockIListener aListener, in AString aAccountId,
  312. //               in flockIBookmark aBookmark, in boolean aPrivate);
  313. // flockIBookmarkWebService
  314. flockDeliciousService.prototype.publish =
  315. function DeliciousSvc_publish(aListener, aAccountId, aBookmark, aPrivate) {
  316.   this._logger.info("Publish (" + aBookmark.URL + "," + aBookmark.name
  317.                     + ") to " + aAccountId + "@Delicious");
  318.   var accountUrn = this.urn + ":" + aAccountId;
  319.   var password = this._acUtils.getPassword(accountUrn);
  320.   var svc = this;
  321.   var tags = aBookmark.tags;
  322.   tags = tags ? tags.split(/[\s,]/).sort().join(" ").replace(/^ /, "") : "";
  323.   var args = {
  324.     url: aBookmark.URL,
  325.     description: aBookmark.name,
  326.     extended: aBookmark.description,
  327.     tags: tags
  328.   };
  329.   if (aPrivate) {
  330.     args.shared = "no";
  331.   }
  332.  
  333.   var deliciousApiListener = {
  334.     onError: function DeliciousSvc_publish_onError(aError) {
  335.       svc._logger.error("posts/add FAILED");
  336.       // BUG: 5705 -  report error via notification bar?
  337.       // onlineFavoritesBackend.showNotification(message);
  338.       if (aListener) {
  339.         aListener.onError(svc, "publish", aError);
  340.       }
  341.     },
  342.     onSuccess: function DeliciousSvc_publish_onSuccess(aXML) {
  343.       svc._logger.info("posts/add SUCCEEDED");
  344.  
  345.       // Validate the nsIDOMDocument response.
  346.       if (!svc._api.isExpectedResponse(aXML, "result")) {
  347.         svc._logger.error("posts/add succeeded - but with invalid xml response");
  348.         // BUG: 5705 -  report error via notification bar?
  349.         // onlineFavoritesBackend.showNotification(message);
  350.         if (aListener) {
  351.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  352.           // FIXME: fill in this flockIError.
  353.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  354.           aListener.onError(svc, "publish", error);
  355.         }
  356.       } else {
  357.         // Process the validated response.
  358.         var result = aXML.documentElement.getAttribute("code");
  359.         svc._logger.debug(" Result for posts/add: " + result);
  360.         if (result == "done") {
  361.           var localBookmarks = svc._coop.get(svc.urn + ":"
  362.                                              + aAccountId + ":bookmarks");
  363.           var tags = aBookmark.tags.split(" ");
  364.           for (i in tags) {
  365.             localBookmarks.tag.addOnce(tags[i]);
  366.           }
  367.           onlineFavoritesBackend.updateBookmark(svc, accountUrn,
  368.                                                 aBookmark, aPrivate);
  369.           if (aListener) {
  370.             aListener.onSuccess(svc, "publish");
  371.           }
  372.         } else if (aListener) {
  373.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  374.           // FIXME: fill in this flockIError.
  375.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  376.           aListener.onError(svc, "publish", error);
  377.         }
  378.       }
  379.     }
  380.   }
  381.  
  382.   this._api.call("posts/add", args, deliciousApiListener, password);
  383. }
  384.  
  385. // void publishList (in flockIListener aListener, in AString aAccountId,
  386. //                   in nsISimpleEnumerator aBookmarkList, in boolean aPrivate);
  387. flockDeliciousService.prototype.publishList =
  388. function DeliciousSvc_publishList(aListener, aAccountId, aBookmarkList, aPrivate) {
  389.   var delay = 1000; // 1 second between each query
  390.   var svc = this;
  391.   var i = 0;
  392.   var bookmarks = [];
  393.  
  394.   var syncCallback = {
  395.     notify: function publishListCallback_notify(timer) {
  396.       var bm = bookmarks.shift();
  397.       svc.publish(aListener, aAccountId, bm, aPrivate);
  398.     }
  399.   }
  400.  
  401.   while (aBookmarkList.hasMoreElements()) {
  402.     var bookmark = aBookmarkList.getNext().QueryInterface(CI.flockIBookmark);
  403.     // Duplicate it because it's going to be removed too early
  404.     bookmarks[i] = {};
  405.     bookmarks[i].URL = bookmark.URL;
  406.     bookmarks[i].name = bookmark.name;
  407.     bookmarks[i].description = bookmark.description;
  408.     bookmarks[i].tags = bookmark.tags;
  409.     bookmarks[i].time = bookmark.time;
  410.  
  411.     this._logger.debug("Set a timer to " + i * delay
  412.                        + " for " + bookmarks[i].URL);
  413.     var publishTimer = CC["@mozilla.org/timer;1"]
  414.                        .createInstance(CI.nsITimer);
  415.     publishTimer.initWithCallback(syncCallback, i * TIMER_SECOND,
  416.                                   CI.nsITimer.TYPE_ONE_SHOT);
  417.     i++;
  418.   }
  419. }
  420.  
  421. // void remove (in flockIListener aListener, in AString aAccountId,
  422. //              in AString aBookmark);
  423. flockDeliciousService.prototype.remove =
  424. function DeliciousSvc_remove(aListener, aAccountId, aBookmark) {
  425.   this._logger.info("Remove " + aBookmark + " from "
  426.                     + aAccountId + "@Delicious");
  427.   var password = this._acUtils.getPassword(this.urn + ":" + aAccountId);
  428.   var svc = this;
  429.   var args = { url: aBookmark };
  430.  
  431.   var deliciousApiListener = {
  432.     onError: function DeliciousSvc_remove_onError(aError) {
  433.       svc._logger.error("posts/delete FAILED");
  434.       // BUG: 5705 -  report error via notification bar?
  435.       // onlineFavoritesBackend.showNotification(message);
  436.       if (aListener) {
  437.         aListener.onError(svc, "remove", aError);
  438.       }
  439.     },
  440.     onSuccess: function DeliciousSvc_remove_onSuccess(aXML) {
  441.       svc._logger.info("posts/delete SUCCEEDED");
  442.  
  443.       // Validate the nsIDOMDocument response.
  444.       if (!svc._api.isExpectedResponse(aXML, "result")) {
  445.         svc._logger.error("posts/delete succeeded - but with invalid xml response");
  446.         // BUG: 5705 -  report error via notification bar?
  447.         // onlineFavoritesBackend.showNotification(message);
  448.         if (aListener) {
  449.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  450.           // FIXME: fill in this flockIError.
  451.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  452.           aListener.onError(svc, "remove", error);
  453.         }
  454.       } else {
  455.         // Process the validated response.
  456.         var result = aXML.documentElement.getAttribute("code");
  457.         svc._logger.debug("Result for posts/delete: " + result);
  458.         if (result == "done") {
  459.           onlineFavoritesBackend.destroyBookmark(svc, aAccountId, aBookmark);
  460.           CC["@flock.com/poller-service;1"].getService(CI.flockIPollerService)
  461.           .forceRefresh(this.urn + ":" + aAccountId + ":bookmarks");
  462.           if (aListener) {
  463.             aListener.onSuccess(svc, "remove");
  464.           }
  465.         } else if (aListener) {
  466.           var error = CC["@flock.com/error;1"].createInstance(CI.flockIError);
  467.           // FIXME: fill in this flockIError.
  468.           error.errorCode = CI.flockIError.FAVS_UNKNOWN_ERROR;
  469.           aListener.onError(svc, "remove", error);
  470.         }
  471.       }
  472.     }
  473.   }
  474.  
  475.   this._api.call("posts/delete", args, deliciousApiListener, password);
  476. }
  477.  
  478. // boolean exists (in AString aAccountId, in AString aURL);
  479. flockDeliciousService.prototype.exists =
  480. function DeliciousSvc_exists(aAccountId, aURL) {
  481.   return this._coop.Bookmark.exists(this.urn + ":" + aAccountId + ":" + aURL);
  482. }
  483.  
  484. // AString getUserURL (in AString aAccountId);
  485. flockDeliciousService.prototype.getUserUrl =
  486. function DeliciousSvc_getUserUrl(aAccountId) {
  487.   return DELICIOUS_USER_URL_BASE + "/" + aAccountId;
  488. }
  489.  
  490.  
  491. /**************************************************************************
  492.  * Flock Delicious Service: flockIPollingService Implementation
  493.  **************************************************************************/
  494.  
  495. // void refresh(in AString aUrn, in flockIPollingListener aListener);
  496. flockDeliciousService.prototype.refresh =
  497. function DeliciousSvc_refresh(aURN, aPollingListener) {
  498.   var svc = this;
  499.   this._logger.info("refresh(" + aURN + ")");
  500.  
  501.   if (!this._coop.OnlineBookmarksStream.exists(aURN)) {
  502.     throw "flockDeliciousService: " + aURN + " can't be found";
  503.   }
  504.  
  505.   var bookmarks = this._coop.get(aURN);
  506.   var accountId = bookmarks.userid;
  507.   var accountUrn = this.urn + ":" + accountId;
  508.   // nsIPassword for auth for this sync
  509.   var password = this._acUtils.getPassword(accountUrn);
  510.  
  511.   var flockListener = {
  512.     onStart: function DeliciousSvc_refresh_onStart(aSubject, aTopic) {
  513.       // Not used.
  514.     },
  515.     onSuccess: function DeliciousSvc_refresh_onSuccess(aSubject, aTopic) {
  516.       svc._logger.info("posts/all SUCCEEDED: " + aTopic);
  517.  
  518.       if (aTopic != "nonew") {
  519.         onlineFavoritesBackend.updateLocal(svc, aSubject, aTopic, accountUrn);
  520.         // Now refresh the tag list (wait one second)
  521.         var syncCallback = {
  522.           notify: function refreshCallback_notify(aTimer) {
  523.             svc._getAllTags(aURN, accountId, password, aPollingListener);
  524.           }
  525.         }
  526.         svc._logger.debug("Setting timer to execute _getAllTags()");
  527.         svc._timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
  528.         svc._timer.initWithCallback(syncCallback, TIMER_SECOND,
  529.                                     CI.nsITimer.TYPE_ONE_SHOT);
  530.         // For "updated" case, syncCallback calls onResult().
  531.       } else if (aPollingListener) {
  532.         aPollingListener.onResult();
  533.       }
  534.     },
  535.     onError: function DeliciousSvc_refresh_onError(aSubject, aTopic, aError) {
  536.       svc._logger.error("posts/all FAILED: ["
  537.                         + aError.errorCode + "] "
  538.                         + aError.errorString + " (["
  539.                         + aError.serviceErrorCode + "] "
  540.                         + aError.serviceErrorString + ")");
  541.  
  542.       var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
  543.                 .getService(Ci.nsIStringBundleService);
  544.       var bundle = sbs.createBundle(DELICIOUS_STRING_BUNDLE);
  545.  
  546.       var message;
  547.       switch (aError.errorCode) {
  548.         case CI.flockIError.FAVS_UNAVAILABLE:
  549.           message = bundle.GetStringFromName("flock.delicious.error.unavailable");
  550.           break;
  551.         case CI.flockIError.FAVS_INVALID_AUTH:
  552.           message = bundle.GetStringFromName("flock.delicious.error.invalid");
  553.           break;
  554.         default:
  555.           message = bundle.formatStringFromName("flock.delicious.error",
  556.                                                 [aError.errorString,
  557.                                                  aError.serviceErrorCode],
  558.                                                 2);
  559.           break;
  560.       }
  561.       // need this delay for the migration case
  562.       // see https://bugzilla.flock.com/show_bug.cgi?id=9051
  563.       var syncCallback = {
  564.         notify: function refreshCallback_notify(timer) {
  565.           onlineFavoritesBackend.showNotification(message);
  566.         }
  567.       }
  568.       svc._timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
  569.       svc._timer.initWithCallback(syncCallback, TIMER_SECOND,
  570.                                   CI.nsITimer.TYPE_ONE_SHOT);
  571.       if (aPollingListener) {
  572.         aPollingListener.onError(aError);
  573.       }
  574.     }
  575.   }
  576.   // even for the first refresh, we need to get the last update time from 
  577.   // the server. Bruno
  578.   this._api.postsUpdate(flockListener, password, bookmarks.last_update_time);
  579. }
  580.  
  581. /**************************************************************************
  582.  * Flock Delicious Service: nsIObserver Implementation
  583.  **************************************************************************/
  584.  
  585. flockDeliciousService.prototype.observe =
  586. function DeliciousSvc_observe(aSubject, aTopic, aState) {
  587.   switch (aTopic) {
  588.     case "xpcom-shutdown":
  589.       var obs = CC["@mozilla.org/observer-service;1"]
  590.                 .getService(CI.nsIObserverService);
  591.       obs.removeObserver(this, "xpcom-shutdown");
  592.       break;
  593.   }
  594. }
  595.  
  596. /**************************************************************************
  597.  * Flock Delicious Service: flockIMigratable Implementation
  598.  * FIXME: Spinoff bug for cleanup of flockIMigrationManager.idl
  599.  **************************************************************************/
  600.  
  601. flockDeliciousService.prototype.__defineGetter__("migrationName",
  602. function DeliciousSvc_getter_migrationName() {
  603.   return "Delicious Accounts";
  604. });
  605.  
  606. // boolean needsMigration(in string oldVersion);
  607. flockDeliciousService.prototype.needsMigration =
  608. function DeliciousSvc_needsMigration(oldVersion) {
  609.   // if online bookmarks webservice is configured AND using delicious
  610.   var pw = this._acUtils.getFirstPasswordForHost(OLD_DELICIOUS_PW_HOST);
  611.   if (PREFS.getPrefType(WEBSERVICE_PREF) &&
  612.       PREFS.getCharPref(WEBSERVICE_PREF) == "delicious")
  613.   {
  614.     if (pw) {
  615.       return true;
  616.     } else {
  617.       return false;
  618.     }
  619.   } else {
  620.     // delicious is not configured so we might as well delete the pm entry
  621.     // since account info is stored in rdf after migration
  622.     if (pw) {
  623.       var pm = CC["@mozilla.org/passwordmanager;1"]
  624.                .getService(CI.nsIPasswordManager);
  625.       pm.removeUser(OLD_DELICIOUS_PW_HOST, pw.user);
  626.     }
  627.     return false;
  628.   }
  629. }
  630.  
  631. // nsISupports startMigration(in string oldVersion,
  632. //                            in flockIMigrationProgressListener aListener);
  633. flockDeliciousService.prototype.startMigration =
  634. function DeliciousSvc_startMigration(oldVersion,
  635.                                      aFlockMigrationProgressListener) {
  636.    var ctxt = {
  637.      listener: aFlockMigrationProgressListener
  638.    };
  639.  
  640.   return { wrappedJSObject: ctxt };
  641. }
  642.  
  643. // boolean doMigrationWork(in nsISupports ctxt);
  644. flockDeliciousService.prototype.doMigrationWork =
  645. function DeliciousSvc_doMigrationWork(ctxt) {
  646.   var context = ctxt.wrappedJSObject;
  647.  
  648.   if (!context.deliciousMigrator)
  649.     context.deliciousMigrator = this._migrateDeliciousAccount(context);
  650.   if (context.deliciousMigrator.next())
  651.     context.deliciousMigrator = null;
  652.  
  653.   return Boolean(context.deliciousMigrator);
  654. }
  655.  
  656. // void finishMigration(in nsISupports ctxt);
  657. flockDeliciousService.prototype.finishMigration =
  658. function DeliciousSvc_finishMigration(ctxt) {
  659. }
  660.  
  661. /**************************************************************************
  662.  * Component: Flock Delicious Account
  663.  **************************************************************************/
  664.  
  665. function flockDeliciousAccount() {
  666.   FlockSvcUtils.getLogger(this).info(".init()");
  667.   FlockSvcUtils.getACUtils(this);
  668.   FlockSvcUtils.getCoop(this);
  669.  
  670.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "deactivate");
  671.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "login");
  672.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "logout");
  673.   FlockSvcUtils.flockIWebServiceAccount.addDefaultMethod(this, "remove");
  674. }
  675.  
  676. /**************************************************************************
  677.  * Flock Delicious Account: XPCOM Component Creation
  678.  **************************************************************************/
  679.  
  680. // Use genericComponent() for the goodness it provides (QI, nsIClassInfo, etc),
  681. // but do NOT add flockDeliciousAccount to the list of constructors passed
  682. // to FlockXPCOMUtils.genericModule().
  683. flockDeliciousAccount.prototype = new FlockXPCOMUtils.genericComponent(
  684.   CLASS_NAME + " Account",
  685.   "",
  686.   "",
  687.   flockDeliciousAccount,
  688.   0,
  689.   [
  690.     CI.flockIWebServiceAccount,
  691.     CI.flockIBookmarkWebServiceAccount,
  692.   ]
  693.   );
  694.  
  695. /**************************************************************************
  696.  * Flock Delicious Account: flockIWebServiceAccount Implementation
  697.  **************************************************************************/
  698.  
  699. // readonly attribute AString urn;
  700. flockDeliciousAccount.prototype.urn = "";
  701.  
  702. // void activate(in flockIListener aListener);
  703. flockDeliciousAccount.prototype.activate =
  704. function DeliciousAcct_activate(aListener) {
  705.   this._logger.debug("activate()");
  706.   this._coop.get(this.urn).isAuthenticated = true;
  707.   this._coop.get(this.urn + ":bookmarks").isPollable = true;
  708.   if (aListener) {
  709.     aListener.onSuccess(this, "activate");
  710.   }
  711. }
  712.  
  713. // DEFAULT: void deactivate(in flockIListener aListener);
  714. // DEFAULT: void login(in flockIListener aListener);
  715. // DEFAULT: void logout(in flockIListener aListener);
  716.  
  717. // void keep();
  718. flockDeliciousAccount.prototype.keep =
  719. function DeliciousAcct_keep() {
  720.   this._logger.debug("keep()");
  721.   this._coop.get(this.urn).isTransient = false;
  722.   this._coop.get(this.urn + ":bookmarks").isTransient = false;
  723.   this._acUtils.makeTempPasswordPermanent(this.urn);
  724. }
  725.  
  726. // DEFAULT: void remove();
  727.  
  728.  
  729. /**************************************************************************
  730.  * Flock Delicious Account: flockIBookmarkWebServiceAccount Implementation
  731.  **************************************************************************/
  732.  
  733. /* No methods or properties on this interface! */
  734.  
  735.  
  736. /**************************************************************************
  737.  * XPCOM Support - Module Construction
  738.  **************************************************************************/
  739.  
  740. // Create array of components.
  741. var gComponentsArray = [flockDeliciousService];
  742.  
  743. // Generate a module for XPCOM to find.
  744. var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MODULE_NAME,
  745.                                                       gComponentsArray);
  746.  
  747. /**************************************************************************
  748.  * END XPCOM Support
  749.  **************************************************************************/
  750.